Участник:Ignatus/patlinkshl.js

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
// Подсвечивает все ссылки на непатрулируемые страницы.
// Если определено Ignatus.hlnp.pagere=/^Портал:(Портал1|Портал2)$/ и т. п.,
//  то работает только на страницах, соответствующих этому РВ (пробелы заменятся подчёркиваниями).
// код частично основан на MediaWiki:Gadget-bkl-check.js
if(typeof Ignatus != 'object')Ignatus={hlnp:{}};
else if(typeof Ignatus.hlnp != 'object') Ignatus.hlnp={};
// **************** Настройки гаджета ****************** //
// Пример: напишите на странице [[Special:MyPage/common.js]] строку (без //)
//  Ignatus = { hlnp: { pagere: new RegExp("^(Проект|Портал):.*/Новые (страницы|статьи)"), noimg: true, stdclasses: true } };
var pagere = Ignatus.hlnp.pagere;// Регулярное выражение имени страницы, где гаджет работает <везде>
var noimg = Ignatus.hlnp.noimg;// Не обрабатывать ссылки, содержащие изображения
var stdclasses = Ignatus.hlnp.stdclasses;// Использовать классы подсветки в СН (проверено для скина Vector)
// ***************************************************** //
if ( mw.config.get('wgNamespaceNumber') >= 0 && ( !pagere || pagere.test( mw.config.get('wgPageName') ) )
    && mw.config.get('wgUserName') && {submit:true, view:true, historysubmit:true, purge:true}[mw.config.get('wgAction')]
) {
// Добавляем классы в начало (переопределите при надобности в [[Special:MyPage/common.css]])
if(!stdclasses)$('head').prepend(
	'<style type=text/css>.unpat-link {background-color: #FFFF80; padding-left: 1px; padding-right: 1px; padding-top: 1px; padding-bottom: 2px}\n'+
	'.totally-unpat-link {background-color: #FFB080; padding-left: 1px; padding-right: 1px; padding-top: 1px; padding-bottom: 2px}</style>');

var patnss = {0:true, 6:true, 10:true, 14:true, 100:true, 828:true}; // Здесь должен быть актуальный список патрулируемых пространств имён

var	className= (stdclasses ? "flaggedrevs-pending" : 'unpat-link'), // Класс для ссылок на статью с непроверенной последней версией
	className2= (stdclasses ? "flaggedrevs-unreviewed" : "totally-unpat-link"), // Класс для ссылок на непатрулировавшуюся статью
	titleAppend = ' (не патрулировано)',
	titleAppend2= ' (не патрулировалось)',
	titleAppend3= ' (непатрулированное перенаправление)',
	titleAppend4= ' (не патрулировавшееся перенаправление)',

	queryUrlPreview= mw.config.get( 'wgScriptPath' ) + '/api.php?action=query&format=json&prop=flagged&indexpageids',
	titles= {}, //{"название страницы":["класс CSS", "что дописать к названию ссылки"],...}
	redirects= {},// Список редиректов по названию
	links,// Доступный всем функциям список элементов-ссылок
	linksfrompg,//Получать страницы из DOM (иначе запрашвать через generator=links)
	count,//счётчик помечаемых страниц
	ta,// Хранилище части имён страниц к запросу
	previewQueryCount,//счётчик ожидаемых запросов, когда вернётся к 0, помечаем
	execute, storeTitles, markLinks, PreviewQuery, getLinks, nsExists;// Функции, кот. нам понадобятся

	nsExists = function(n) {
      return mw.config.get('wgNamespaceIds')[n.toLowerCase().replace(/\s/g,"_")]
    }
    storeTitles = function ( res ) {// Запись в titles и redirects результатов запроса к API
		if ( !res || !res.query || !res.query.pageids ) return;
		var q = res.query; var pids=q.pageids;var i;
		var ra;// Массив-накопитель редиректов
		// Если редирект не патрулирован, показываем его статус и направляем ссылку без перехода.
		// Если патрулирован, то потом запросим и покажем статус статьи.
		if(q.redirects){// Если вызываем для набора перенаправлений
			var rdlist = q.redirects; // [{from:'редирект',to:'куда'},...]
			ra={};// Здесь переводим в ассоциативную базу
			for ( i=0; i<rdlist.length; i++) ra[rdlist[i].to]=rdlist[i].from;//{статья:перенаправление, ...}
		}
		for ( i = 0; i < pids.length; i++ ) {
			var page = q.pages[pids[i]];
			var isrd = page.title in redirects;
			if ( page.missing === '' || !patnss[page.ns] ) continue;// Не обрабатываем чужие п. и.
			if ( page.flagged && !page.flagged.pending_since ) continue; //Патрулировано
			else if (isrd) delete redirects[page.title];// Непатрулированное перенаправление не надо запрашивать
			count++;
			titles[ 'redirects' in q ? ra[page.title] : page.title ] = page.flagged
			 ? [ className,  ( isrd?titleAppend3:titleAppend  ).replace( ')', ' с ' + page.flagged.pending_since + ')' ) ]
			 : [ className2, ( isrd?titleAppend4:titleAppend2 ) ];
		}
	};

	markLinks = function () {// Собственно, отобразить пометки
		if ( !count ) return;
		if ( !links ) return;
		for ( var i = 0; i < links.length; i++ ) {
			// Do not mess with images and user-specified objects
			if ( /image/.test( links[i].className) || noimg && $(links[i]).find('img').length )continue;

			var tpl = titles[links[i].title];
			if ( !tpl ) continue;
			// Помещаем внутренность ссылки в цветной span
			$(links[i]).wrapInner('<span class="' + tpl[0] + '" title="'+links[i].title+tpl[1]+'"></span>');
			if(tpl[1].indexOf('перенапр')!=-1)links[i].href+=(links[i].href.indexOf('?')==-1?'?':'&')+'redirect=no';
			//Если это непатрулированное перенаправление, то меняем ссылку на статью на ссылку на редирект
		}
	};

	PreviewQuery = function ( titles, wut ) {//Конструктор запроса к БД, используется для предпросмотра и редиректов
		previewQueryCount++;//Размечать будем, когда придут все ответы
		//We have to keep the titles in memory in case we get a query-continue
		this.data ='titles='+ titles.join( '|' );// Редиректы запрашиваем по pageids, остальное - по titles
		this.doQuery( queryUrlPreview + wut );
	};

	execute = function ($content) {// Получаем список ссылок в предпросмотре и делаем по ним запросы
		links = getLinks( $content );
		count=0;
		previewQueryCount=0;
		if ( !links ) return;
		ta=[]; var m, m1;
		linksfrompg = mw.config.get('wgAction')!=='view' || mw.config.get('wgNamespaceNumber')===14;
		// В режиме просмотра получать ссылки быстрее через generator=links, если это не категория
		var unique = {};
		var rxEscape = function(s) {return s.replace( /([\/\.\*\+\?\|\(\)\[\]\{\}\\])/g, '\\$1' );};
		var siteRegex = new RegExp( rxEscape( mw.config.get('wgServer') ).replace( "\\.wiki","(\\.m)?\\.wiki") // для мобильных версий 
		 + rxEscape( mw.config.get('wgArticlePath').replace( /\$1/, '' ) ) + '([^#]*)' );
		var patnsregex = new RegExp("^(|Шаблон|Файл|Модуль|Категория|Портал)$");// Здесь должен быть актуальный список патрулируемых п. и.
		//We only care for some ns pages, so we can filter out the most common cases to save some requests
		
		for ( var i = 0; i < links.length; i++ ) {//Помещаем в локальную titles базу заголовков
            if (!links[i].title || !( m = decodeURI(links[i].href).match( siteRegex ) ) || ( m1=m[2].match('^([^:]+):') )
				&& ( !m1[1].match( patnsregex ) && nsExists(m1[1]) )
                || unique[m[2]] || noimg && $(links[i]).find('img').length ) continue;
			unique[m[2]] = true; //Avoid requesting same title multiple times
			if( $(links[i]).hasClass('mw-redirect') ) redirects[links[i].title] = true;//Запоминаем, что это редирект
			if(linksfrompg){
				ta.push( m[2].replace( /_/g, '%20' ) ); //Avoid normalization of titles // Надо ли?
				if ( ta.length < 50 ) continue;// Лимит заглавий 50
				new PreviewQuery( ta, '' );
				ta =[];
			}else linksfrompg=null;//Сигнал, что что-то есть
		}
		if ( ta.length ) new PreviewQuery( ta, '' );
		else if(linksfrompg===null){
			for(i in patnss){
				ta.push(String(i));
			}
			new PreviewQuery([mw.config.get('wgPageName')] ,'&generator=links&gpllimit=max&gplnamespace='+ta.join('|'));
		}
	},

	getLinks = function ( el ) {
		return el && el.find( 'a' );
	};

PreviewQuery.prototype.doQuery = function( url ) {
	var q = this;
	$.ajax( {
		url: url,
		method: 'POST',
		contentType: 'application/x-www-form-urlencoded',
		data: q.data,
		success: function( data, textStatus, jqXHR ) {
			q.resultArrived( data );
		}
	} );
};

PreviewQuery.prototype.resultArrived = function ( res ) {//Обработка запроса в предпросмотре
	storeTitles( res );
	if ( res && res.continue ) {//Не уложились в лимит
		var c=res.continue;
		var url = queryUrlPreview + 
			'&gplcontinue=' + encodeURIComponent( c.gplcontinue ) +
			'&continue=' + encodeURIComponent( c.continue );
		if(!linksfrompg)url+='&generator=links&gpllimit=max&gplnamespace='+ta.join('|');// Если продолжаем запрос ссылок из БД
		if(res.query && res.query.redirects) url += '&redirects'; // Если продолжаем запрос редиректов
		this.doQuery( url );// Посылаем продолженный запрос по тем же страницам в this.data
	} else {//Все данные по текущему набору получены, уменьшаем счётчик запросов
		if( !--previewQueryCount ){// Все запросы выполнены
			if(!(res.query && res.query.redirects)){//обрабатываем редиректы, если мы не этим занимались
				var rids=[];
				for(var rid in redirects){
					rids.push(rid);
					if(rids.length<50)continue;
					new PreviewQuery(rids, '&redirects');//Запрашиваем редиректы
					rids=[];
				}
				if(rids.length)new PreviewQuery(rids, '&redirects');
			}
			if( !previewQueryCount ) markLinks();//Если редиректы не запущены, размечаем
		}
	}
};

mw.hook('wikipage.content').add( execute );
}//if